home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Graphics / NXPlot3d / Source / Expression.h < prev    next >
Text File  |  1993-10-12  |  12KB  |  288 lines

  1.  
  2. #import <objc/Object.h>
  3. #import <objc/hashtable.h>
  4. #import <appkit/errors.h>
  5.  
  6.  /*
  7.   * An Expression object parses and evaluates the text of a mathematical
  8.   * expression.  The expression text may contain numbers, variables,
  9.   * arithmetic operations and program defined functions.  For example,
  10.   * an Expression object can parse the string "a+b*c", and if told
  11.   * values for a, b and c, can calculate the value of the expression.
  12.   *
  13.   * This ability to parse and evaluate expressions at runtime makes it
  14.   * easy for simple mathmatical programs to move beyond having canned example
  15.   * functions compiled into their executables, and instead allow the user
  16.   * to enter novel equations.  New formulas can be tried without recompiling
  17.   * the application.
  18.   * 
  19.   * Typically an Expression is created and then told to parse some text
  20.   * entered by the user.  The result of the parse is a parse tree, which is
  21.   * then used by the Expression to evaluate the expression, given a set
  22.   * of values for the expression's variables.  Variables can have either a
  23.   * single value, or can be made to take on a series of values ("vector
  24.   * variables").  For example, if you were graphing "A*x^2", you might
  25.   * make A have a single value, but let x run over a range of
  26.   * values that you would like to plot.
  27.   *
  28.   * The values of these vector variables can be set in two ways.  In the
  29.   * first way, a list of values is passed in using the setVar:vector:numVals: 
  30.   * method.  In the second way, the variable is given a range for its
  31.   * values with the setVar:min:max: method.  The actual values are then
  32.   * interpolated within that range.  The resolution of the expression
  33.   * determines how many values are calculated.  If you mix these two styles
  34.   * of vector variables, you must ensure that the number of explicitly
  35.   * set values assigned to any variables matches the resolution of the
  36.   * Expression.
  37.   *
  38.   * If there are more than one range-style vector variables in an Expression
  39.   * they may be interpolated together or orthogonally, creating
  40.   * multi-dimensional domains.  You can set the total number of dimensions over
  41.   * which the expression is evaluated, and then set the dimension of each
  42.   * vector variable that is being interpolated.
  43.   *
  44.   * Expressions always operate lazily, meaning that results are never
  45.   * calculated until they are needed (usually when result values are asked
  46.   * for). This means just changing the values of variables is inexpensive.
  47.   *
  48.   * Expressions have methods which allow an application to enumerate the
  49.   * names of all the variables found by the parse.  This can be used to verify
  50.   * that the expression is valid, beyond whether it was parsable.  For
  51.   * example, in a certain context there may be a fixed set of variable names
  52.   * that may be used.  After a successful parse, the application can run
  53.   * through the names of all variables found, and ensure that they are all
  54.   * appropriate.
  55.   *
  56.   * Expressions understand the arithmetic operators +, -, *, /.  % is used
  57.   * for modulus (as in C) and ^ means is used to raise a quantity to a power.
  58.   * Parentheses can be used for grouping.
  59.   *
  60.   * Expressions have certain "built in" functions (e.g., sin()) that are
  61.   * understood.  It is also possible for applications to extend this default
  62.   * set of functions.  New functions are registered with the name of the
  63.   * function, the allowable number of arguments (can be variable), and a C
  64.   * procedure to call to perform the evaluation.  The built in functions are:
  65.   *
  66.   *    sin(x), cos(x), tan(x)        - elementary trig
  67.   *    asin(x), acos(x), atan(x)     - inverse elementary trig
  68.   *    exp(x), ln(x)            - exponential and natural log
  69.   *    sqrt(x)                - square root
  70.   *
  71.   * The constants "pi" and "e" are also built in.
  72.   */
  73.  
  74. /* function supplied by term implementor for evaluation */
  75. typedef float EXPTermEvalFunc(int numArgs, float *args);
  76.  
  77. /* enumeration state used to loop through all the variable names */
  78. typedef void *EXPEnumState;
  79.  
  80. /* private type for representing terms */
  81. typedef struct _EXPTerm *EXPTermPtr;
  82.  
  83. @interface Expression : Object {
  84.     char *text;            /* text of the expression */
  85.     NXHashTable *varTerms;    /* terms of variables */
  86.     EXPTermPtr parseTree;    /* terms from the parse */
  87.     NXHashTable *validFuncs;    /* functions we know how to evaluate */
  88.     int resolution;        /* number of points to calc for range vars */
  89.     BOOL resultsValid;        /* are the results up to date? */
  90.     short dimensions;        /* #axes of evaluation, defaults to 1 */
  91.     float *results;        /* results of evaluation */
  92.     float resultsMin;        /* min of all results */
  93.     float resultsMax;        /* max of all results */
  94. }
  95.  
  96. - init;
  97.  /*
  98.   * Initialize an Expression that was just created via "allocFromZone:".  You
  99.   * cannot use a "+new" method to create Expression objects.  Below are some
  100.   * examples of creating Expressions.  The first expression goes in the 
  101.   * default malloc zone, the second is allocated in the same zone as
  102.   * otherObject.
  103.   *
  104.   *    id myExp1, myExp2;
  105.   *    myExp1 = [[Expression alloc] init];
  106.   *    myExp2 = [[Expression allocFromZone:[otherObject zone]] init];
  107.   *
  108.   */
  109.  
  110. - free;
  111.  /*
  112.   * Frees the Expression, including any array of results returned by
  113.   * the resultsVector:numVals: method.
  114.   */
  115.  
  116. - (BOOL)parse:(const char *)expressionString;
  117.  /*
  118.   * Parses the text of an expression.  A parse tree of terms is built up as
  119.   * a result of parsing expressionString.  The method returns whether the
  120.   * string was a legal expression.  expressionString is copied and retained
  121.   * within the Expression.
  122.   */
  123.  
  124. - (const char *)text;
  125.  /*
  126.   * Returns the last text parsed by the Expression.
  127.   */
  128.  
  129. - setResolution:(int)count;
  130.  /*
  131.   * Sets the resolution at which variables with a min and max range will
  132.   * be subdivided.  All vectors in the Expression must have the same
  133.   * number of values, which must be equal to the resolution of the
  134.   * Expression, at the time the Expression is evaluated.  Note that setting
  135.   * the list of values of a vector variable also changes the Expression's
  136.   * resolution.
  137.   */
  138.  
  139. - (int)resolution;
  140.  /*
  141.   * Returns the resolution of the Expression.
  142.   */
  143.  
  144. - setVar:(const char *)varName value:(float)val;
  145.  /*
  146.   * Sets the value of the variable named varName to val.  The variable
  147.   * will have that value as a constant throughout subsequent evaluations.
  148.   */
  149.  
  150. - (float)varValue:(const char *)varName;
  151.  /*
  152.   * Returns the value of the variable varName.  If the variable is being
  153.   * used as a vector, then its first value is returned.
  154.   */
  155.  
  156. - setVar:(const char *)varName vector:(float *)vals numVals:(int)count;
  157.  /*
  158.   * Sets the values of the variable named varName to be the array
  159.   * vals.  Count is the number of values in the vector.  This method
  160.   * also sets the resolution of the Expression to be count.
  161.   * All vectors in the Expression must have the same number of values,
  162.   * which must be equal to the resolution of the Expression, at the
  163.   * time the Expression is evaluated.  The list of vals should be a block
  164.   * of floats returned from malloc.  It is NOT copied, but will be freed by
  165.   * the Expression as part of its own free method.
  166.   */
  167.  
  168. - varVector:(const char *)varName vector:(float **)vals numVals:(int *)count;
  169.  /*
  170.   * Returns the vector of values of the variable varName by setting
  171.   * vals to point to the vector.  Count is set to the number of values.
  172.   */
  173.  
  174. - setVar:(const char *)varName min:(float)minVal max:(float)maxVal;
  175.  /*
  176.   * Sets the range of the variable varName to run from minVal to maxVal.
  177.   * The variables values will be determined by interpolating points
  178.   * within this range.  The resolution of the Expression determines the
  179.   * number of points that are taken within the range.
  180.   */
  181.  
  182. - setVar:(const char *)varName dimension:(short)dimensionNum;
  183.  /*
  184.   * Sets the dimension within which the variable will vary.  The given value
  185.   * must be between 0 and [expression dimensions]-1.
  186.   */
  187.  
  188. - var:(const char *)varName dimension:(short *)dimensionNum;
  189.  /*
  190.   * Returns the dimension within which the variable will vary.
  191.   */
  192.  
  193. - var:(const char *)varName min:(float *)minVal max:(float *)maxVal;
  194.  /*
  195.   * Returns the smallest and largest value of the variable varName by setting
  196.   * minVal and maxVal.
  197.   */
  198.  
  199. - (float)resultValue;
  200.  /*
  201.   * Returns the value of the Expression when evaluated with its current
  202.   * attributes.  If there are vector variables in the Expression, it
  203.   * returns the result using the first value of all vectors.
  204.   */
  205.  
  206. - resultsVector:(float **)vals numVals:(int *)count;
  207.  /*
  208.   * Returns the values of the Expression when evaluated with its current
  209.   * attributes, by setting vals to point to the vector of results.  count
  210.   * is set to the number of results.  The number of results returned will be
  211.   * resolution^dimensions.  If there are no vector variables in the
  212.   * Expression, a single result is returned.
  213.   */
  214.  
  215. - resultsMin:(float *)minVal max:(float *)maxVal;
  216.  /*
  217.   * Returns the smallest and largest value of the results by setting
  218.   * minVal and maxVal.
  219.   */
  220.  
  221. - setDimensions:(short)count;
  222.  /*
  223.   * Sets the number of evaluation dimensions.  The number of values in the
  224.   * results vector is resolution^dimensions.  A given variable varies in one
  225.   * dimension, as set by setVar:dimension:.
  226.   */
  227.  
  228. - (short)dimensions;
  229.  /*
  230.   * Returns the number of evaluation dimensions.
  231.   */
  232.  
  233. - (EXPEnumState)beginVariableEnumeration;
  234. - (const char *)nextVariable:(EXPEnumState)state;
  235. - (void)endVariableEnumeration:(EXPEnumState)state;
  236.  /*
  237.   * Used to walk through the names of all variables parsed.  Example:
  238.   *     EXPEnumState state = [myExp beginVariableEnumeration];
  239.   *    const char *varName;
  240.   *    while (varName = [myExp nextVariable:state])
  241.   *        printf("A variable named %s was parsed.\n", varName);
  242.   *    [myExp endVariableEnumeration:state];
  243.   */
  244.  
  245. - addFuncTerm:(const char *)name minArgs:(int)min maxArgs:(int)max
  246.                     evalFunc:(EXPTermEvalFunc *)func;
  247.  /*
  248.   * Adds a function to the set of functions this Expression can parse.
  249.   * Functions look like "name(arg1, arg2,...)" in the text that is
  250.   * parsed.  At evaluation time the C function func() will be called with
  251.   * the values of the arguments.  The arguments are passed in an array of
  252.   * floats(see the EXPTermEvalFunc typedef above).  Func must return the value
  253.   * of the function with those arguments. min and max determine how many
  254.   * arguments the function can accept.  For example, min=1, max=1 means
  255.   * the function takes one argument.  A max value of -1 means an unbounded
  256.   * number of arguments is allowed.
  257.   */
  258.  
  259. - removeFuncTerm:(const char *)name;
  260.  /*
  261.   * Removes a function from the set of functions this Expression can parse.
  262.   * Be careful not to send this to an Expression that has already parsed
  263.   * text which made use of this function, since a reference to this FuncTerm
  264.   * will be left dangling in the parse tree.
  265.   */
  266.  
  267. @end
  268.  
  269. /* Error codes we raise */
  270.  
  271. typedef enum {
  272.     expErrInvalidVarName = NX_APPBASE + 10000,
  273.       /* An argument was passed referring to a variable whose name did not exist in the expression parsed. */
  274.     expErrInvalidVarType,
  275.       /* A variable was used in a way inconsistent with its type. */
  276.     expErrMinMax,
  277.       /* A min parameter was not less that its accompanying max parameter. */
  278.     expErrNoText,
  279.       /* A method could not complete because no expression had been parsed. */
  280.     expErrResolutionMismatch,
  281.       /* The number of points in the vector terms and the resolution of the Expression are inconsistent. */
  282.     expFuncTypeInUse,
  283.       /* A message was sent attempting to add a function which has already been declared. */
  284.     expInvalidDimension
  285.       /* A invalid value for a var's dimension was passed. */
  286. } EXPError;
  287.  
  288.